Skip to content

fix(types): align public API types with what the code returns - #955

Merged
robwoodgate merged 2 commits into
test/typecheck-gatefrom
fix/api-type-defects
Aug 12, 2026
Merged

fix(types): align public API types with what the code returns#955
robwoodgate merged 2 commits into
test/typecheck-gatefrom
fix/api-type-defects

Conversation

@robwoodgate

@robwoodgate robwoodgate commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #954. Base is test/typecheck-gate, so review only the second commit; GitHub will retarget to main once #954 merges.

Description

Type checking the test tree (#954) surfaced five places in src/ where a declared type asserts more than the implementation delivers. Four were held open by an as cast, which is why the compiler never objected: as unknown as appears exactly twice in the whole of src/, and one of the two was a defect.

Changes

  • PaymentRequest.decodePayload returned amount: Amount.from(x).toBigInt(), a raw bigint, behind as unknown as Proof, while PaymentRequestPayload.proofs has always declared Proof[] (so amount: Amount). A consumer following the types into payload.proofs[0].amount.toBigInt() got a runtime TypeError, and encodePayload disagreed with its own decoder about what a payload proof is. It now normalizes to Amount and the cast is gone. The API report is unchanged for this: the declared type was always right, only the implementation lied.
  • PrepareMeltConfig folded into MeltProofsConfig and deleted. It was added incidentally to widen one prepareMelt signature when nut08Change arrived, carried no docblock, and had a single use. The four public melt helpers took MeltProofsConfig and forwarded it wholesale, so nut08Change worked at runtime through all of them but could not be expressed in TypeScript. Since the field is optional, folding it in changes nothing for existing callers, and it fixes the gap by making the API smaller rather than widening four signatures.
  • createLockedMintQuote throws unless the mint echoes a pubkey, then returns it, but declared MintQuoteBolt11Response where pubkey is optional. The return now carries it, removing the non-null assertions at call sites.
  • NUT10Option.tags and RawNUT10Option.t are now optional. NUT-10 marks tags optional and NUT-18 says "t: optional NUT-10 payment tags". CTS's own internal Nut10SpendingCondition in utils/tlv.ts already declared it optional, with a parser that deliberately returns undefined when absent, and every read site guards with ?? []. Decoding a spec-valid request without tags therefore produced an object that violated its own declared type.
  • The bolt11 mint quote state is marked @deprecated, pointing at amount_paid / amount_issued. The docblock already said "deprecated" in prose, but nothing machine-readable expressed it. It stays populated for backwards compatibility.

Reviewer Notes

  • decodePayload is the only behavioural change. Exactly the two tests that had asserted the bigint shape failed, and are updated along with the doc line that described it.
  • Compatibility: decodePayload now hands back Amount where it used to hand back bigint, and PrepareMeltConfig is removed from the public surface. Both only affect the v5 rc line, so I have not marked this a breaking change
  • The stale as PrepareMeltConfig workaround introduced in test: type check the test tree and fix fixture drift #954 comes back out here, which is a decent check that the gap is genuinely closed.
  • Not fixed, deliberately: CTSError.cause is declared readonly but defined writable: true at runtime. That mismatch is intentional and a test asserts the descriptor.

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.76%. Comparing base (ced752f) to head (2a569ba).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@                 Coverage Diff                  @@
##           test/typecheck-gate     #955   +/-   ##
====================================================
  Coverage                95.76%   95.76%           
====================================================
  Files                       55       55           
  Lines                     5781     5781           
  Branches                  1465     1465           
====================================================
  Hits                      5536     5536           
  Misses                     104      104           
  Partials                   141      141           
Flag Coverage Δ
integration 37.75% <0.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

The test-tree type check surfaced several places where a declared type asserts
more than the implementation delivers, each held open by an 'as' cast.

- decodePayload returned a raw bigint amount behind 'as unknown as Proof',
  while PaymentRequestPayload.proofs has always declared Proof[]. It now
  normalizes to Amount, so the runtime matches the declared type
- fold nut08Change into MeltProofsConfig and drop PrepareMeltConfig. The public
  melt helpers forward their config to prepareMelt, so the option already worked
  at runtime but could not be expressed
- createLockedMintQuote throws unless the mint echoes a pubkey, so its return
  now carries one
- NUT10Option.tags and RawNUT10Option.t are optional per NUT-10 and NUT-18, and
  every read site already guarded for it
- mark the bolt11 mint quote state deprecated in favour of the accounting
  fields
@robwoodgate
robwoodgate merged commit 98f8994 into main Aug 12, 2026
19 checks passed
@robwoodgate
robwoodgate deleted the fix/api-type-defects branch August 12, 2026 19:22
@github-project-automation github-project-automation Bot moved this from Backlog to Done in cashu-ts Aug 12, 2026
robwoodgate added a commit that referenced this pull request Aug 12, 2026
## Description

Two public type corrections carried back from the v5 line (#955), shaped
so that nothing is removed from this stable major. The point is partly
the fixes themselves and partly keeping the two lines' type shapes
aligned so future backports apply cleanly.

## Changes

- **`nut08Change` moves onto `MeltProofsConfig`.** `meltProofs`,
`meltProofsBolt11`, `meltProofsBolt12` and `meltProofsOnchain` all take
`MeltProofsConfig` and forward it wholesale to `prepareMelt`, which took
the wider `PrepareMeltConfig`. So the option already worked at runtime
through every helper but could not be expressed in TypeScript.
`PrepareMeltConfig` remains, as a deprecated alias of
`MeltProofsConfig`, so no import breaks.
- **`NUT10Option.tags` and `RawNUT10Option.t` are optional.** NUT-10
marks `tags` optional and NUT-18 describes `t` as "optional NUT-10
payment tags". The implementation already agreed: `utils/tlv.ts`
declares its internal `Nut10SpendingCondition.tags` optional and
deliberately returns `undefined` when absent, and every read site guards
with `?? []` or a length check. Decoding a spec-valid request that omits
tags therefore produced an object that violated its own declared type.

## Reviewer Notes

- Nothing is removed from the public surface. The API report diff is
additive apart from the two fields becoming optional and
`PrepareMeltConfig` collapsing to an alias.
- The one compatibility wrinkle: TypeScript consumers who *read*
`nut10.tags` now see `string[][] | undefined` and need a guard. That is
the truth they were already exposed to at runtime, and
`PaymentRequestTransport.tags` on this line is already optional, so it
also removes an internal inconsistency.
- In v5 `PrepareMeltConfig` is removed outright rather than aliased,
which the v5 migration guide now records.
- Verified on this branch: `src/` type checks clean, node suite passes
62 files and 2077 tests, lint and format clean, `api:update` run and
committed.
robwoodgate added a commit that referenced this pull request Aug 12, 2026
Mostly a hardening release: input validation and parsing fixes across auth, crypto, transport and wallet. It also adds CounterSource.reserveAt for claiming manual counter ranges atomically, dual-licenses the package MIT OR Apache-2.0, and carries six breaking changes since rc.5, all documented in the migration guide.

---

##
[5.0.0-rc.6](v5.0.0-rc.5...v5.0.0-rc.6)
(2026-08-12)


### Features

* **wallet:** claim manual counter ranges up front with
CounterSource.reserveAt
([#923](#923))
([8bee5dc](8bee5dc))


### Bug Fixes

* **auth:** coerce the device-flow polling interval to a finite value
([#929](#929))
([d2c3d9f](d2c3d9f))
* **auth:** detach the OIDC token listener when the provider is replaced
([#939](#939))
([ae9ea8b](ae9ea8b))
* **auth:** drop a CAT refresh that completes after the session changes
([#927](#927))
([7443daf](7443daf))
* **auth:** stop following redirects on token-bearing requests
([#926](#926))
([ac80863](ac80863))
* **auth:** validate OIDC provider URLs use an http(s) scheme
([#896](#896))
([11cf24d](11cf24d))
* **crypto:** bound pow2height in createNewMintKeys at runtime
([#938](#938))
([5bade9a](5bade9a))
* **crypto:** bound the deterministic counter to the safe integer range
([#919](#919))
([54871f6](54871f6))
* **crypto:** count unique signers by x-only pubkey identity
([#904](#904))
([673468f](673468f))
* **crypto:** harden HTLC witness parsing edge cases
([#892](#892))
([52b51ea](52b51ea))
* **crypto:** require a 64-byte seed and slim the seed error context
([#920](#920))
([640b8fe](640b8fe))
* **crypto:** tighten NUT-10 secret and tag-integer parsing
([#893](#893))
([6e1dfaf](6e1dfaf))
* **crypto:** validate the blind point in the BLS signer
([#931](#931))
([4b49e08](4b49e08))
* guard CBOR and keyset map lookups against prototype-chain keys
([#895](#895))
([3798e44](3798e44))
* **logger:** escape control characters in log messages
([#906](#906))
([cc89ad3](cc89ad3))
* **mintinfo:** bound mint-advertised method and endpoint lists
([#928](#928))
([2647472](2647472))
* **p2bk:** share one ephemeral key across a blinded SIG_ALL batch
([#946](#946))
([9189f36](9189f36))
* tidy response reads and number-token parsing
([#886](#886))
([24e1593](24e1593))
* **token:** return per-proof amounts, not proofs, from getTokenMetadata
([#941](#941))
([2f00216](2f00216))
* **types:** align public API types with what the code returns
([#955](#955))
([98f8994](98f8994))
* **utils:** align base64 fallback chunk size to a 3-byte boundary
([#905](#905))
([6107ad7](6107ad7))
* **utils:** cap JSON nesting depth in JSONInt.parse
([#907](#907))
([c7b3589](c7b3589))
* **wallet:** check bolt11 quote amounts against the invoice
([#925](#925))
([503ea70](503ea70))
* **wallet:** harden P2PK spending-condition locktime and tag validation
([#894](#894))
([6985fa1](6985fa1))
* **wallet:** name the offending index when rejecting duplicate proofs
([#917](#917))
([308d441](308d441))
* **wallet:** reject duplicate proofs before totalling or selecting
([#916](#916))
([dd34ef9](dd34ef9))
* **wallet:** reject extraPayload keys reserved by the melt request
([#908](#908))
([e85314e](e85314e))
* **ws:** ignore socket events from a replaced connection
([#930](#930))
([f6c8775](f6c8775))


### Performance Improvements

* **wallet:** look up keyset unit by map instead of scanning ids
([#909](#909))
([ec6fc8b](ec6fc8b))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant